package com.lap.tool.starter.holder;

import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Spring 工具类
 *
 * @author Shuisheng Lao(劳水生)
 * @version 0.0.1
 */
public class SpringHolder implements ApplicationContextAware {
  private static final Map<Class<? extends Annotation>, String[]> BEAN_NAME_CACHE =
      new ConcurrentHashMap<>();

  private static ApplicationContext context;

  @Override
  public void setApplicationContext(ApplicationContext applicationContext) {
    if (context == null) {
      context = applicationContext;
    }
  }

  /**
   * 根据注解类型，指定返回类型,获取实例
   *
   * @param annotationClass 注解类型
   * @return 对象集合
   */
  public static List<Object> getBeansWithAnnotation(Class<? extends Annotation> annotationClass) {
    validateContextInitialized();
    Objects.requireNonNull(annotationClass, "Annotation type must not be null");

    String[] beanNames =
        BEAN_NAME_CACHE.computeIfAbsent(
            annotationClass, key -> context.getBeanNamesForAnnotation(key));

    return Arrays.stream(beanNames)
        .map(context::getBean)
        .map(SpringHolder::unwrapProxy)
        .filter(Objects::nonNull)
        .toList();
  }

  /**
   * 根据注解类型，指定返回类型,获取实例
   *
   * @param annotationClass 注解类型
   * @param targetType 返回类型
   * @param <T> 类型
   * @return 对象集合
   */
  public static <T> List<T> getBeansWithAnnotation(
      Class<? extends Annotation> annotationClass, Class<T> targetType) {
    validateContextInitialized();
    Objects.requireNonNull(annotationClass, "Annotation type must not be null");
    Objects.requireNonNull(targetType, "Target type must not be null");

    String[] beanNames =
        BEAN_NAME_CACHE.computeIfAbsent(
            annotationClass, key -> context.getBeanNamesForAnnotation(key));

    return Arrays.stream(beanNames)
        .map(context::getBean)
        .map(SpringHolder::unwrapProxy)
        .filter(Objects::nonNull)
        .filter(targetType::isInstance)
        .map(targetType::cast)
        .toList();
  }

  private static Object unwrapProxy(Object bean) {
    if (!AopUtils.isAopProxy(bean)) {
      return bean;
    }

    try {
      // 处理 Spring 的 Advised 代理对象
      if (bean instanceof Advised advised) {
        Object target = advised.getTargetSource().getTarget();
        return unwrapProxy(target); // 递归解包多层代理
      }
      // 处理其他类型代理（如 JDK 动态代理）
      return AopProxyUtils.getSingletonTarget(bean);
    } catch (Exception e) {
      throw new IllegalStateException("无法解包代理对象: " + bean.getClass(), e);
    }
  }

  private static void validateContextInitialized() {
    if (context == null) {
      throw new IllegalStateException("ApplicationContext not initialized");
    }
  }

  /**
   * 根据Bean获取实例
   *
   * @param <T> 实例类型
   * @param clazz 类型
   * @return 对象类型
   */
  public static <T> T getBeanByType(Class<T> clazz) {
    return context.getBean(clazz);
  }
}
